package org.lzuploader.gui.listeners.login;


import java.security.NoSuchAlgorithmException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Shell;
import org.lzuploader.controller.Md5;
import org.lzuploader.controller.NetUploader;
import org.lzuploader.controller.ResultParser;
import org.lzuploader.exception.ThreadAlreadyRunningException;
import org.lzuploader.gui.WLogin;
import org.lzuploader.gui.WRecap;
import org.lzuploader.gui.WWait;
import org.lzuploader.gui.helpers.EasyMessageBox;
import org.lzuploader.model.Config;
import org.lzuploader.model.Localization;
import org.lzuploader.model.account.Account;
import org.lzuploader.model.account.AccountServerConfig;
import org.lzuploader.model.result.Result;

/**
 * This class is used when the user validates his modifications on options page.
 * @author Emmanuel Cron
 *
 */
public class OkSelectionListener implements SelectionListener
{
    /** The logger of this class. */
    private Log log = LogFactory.getLog(OkSelectionListener.class);
    
    /** Localization of this class. */
    private Localization localization = Localization.getInstance();
    
    /** Used when widget is selected by default.
     * @param e Associated event
     */
    @Override
    public void widgetDefaultSelected(final SelectionEvent e)
    {
        widgetSelected(e);
    }

    /** Used when widget is manually selected.
     * @param e Associated event
     */
    @Override
    public void widgetSelected(final SelectionEvent e)
    {
        log.debug("Validating options.");
        
        log.trace("Fetching data.");
        
        Shell wLoginShell = null;
        for (int i = 0 ; i < e.display.getShells().length ; i++)
        {
            if (e.display.getShells()[i].getData() instanceof WLogin)
            {
                wLoginShell = e.display.getShells()[i];
                break;
            }
        }
        
        processAuthentificationAndUpload(wLoginShell, true);
    }
    
    /**
     * Validates an authentification and launches the upload process.
     * Using this function will make the password not to be hashed before upload.
     * @param wLoginShell The shell of the login window.
     */
    public void processAuthentificationAndUpload(final Shell wLoginShell)
    {
        processAuthentificationAndUpload(wLoginShell, false);
    }
    
    /**
     * Validates an authentification and launches the upload process.
     * @param wLoginShell The shell of the login window.
     * @param hashPassword Tells the function to hash the password or not
     */
    private void processAuthentificationAndUpload(final Shell wLoginShell, final boolean hashPassword)
    {
        final WLogin wLogin = (WLogin) wLoginShell.getData();
        final String login = wLogin.getLoginText().getText();
        final String pwd = wLogin.getPasswordText().getText();
        
        log.trace("Reseting password field for security reasons.");
        wLogin.getPasswordText().setText("");
        
        if (login.length() < 1 || pwd.length() < 1)
        {
            log.trace("Login or password length is < 1, displaying a message box and returning.");
            
            EasyMessageBox.info(
                localization.getString("DIALOG_TITLE_INFO"),
                localization.getString("DIALOG_LOGIN_AND_PWD_REQUIRED")
            );
            
            return;
        }
        
        log.trace("Login and password ok.");
        
        final String pwdMd5;
        
        if (hashPassword)
        {
            log.trace("Hashing password with md5 algorithm.");
            
            try
            {
                pwdMd5 = Md5.convert(pwd);
            }
            catch (final NoSuchAlgorithmException nsae)
            {
                log.error("md5 algorithm could not be found, displaying an error and returning.");
                
                EasyMessageBox.error(
                    localization.getString("DIALOG_TITLE_ERROR"),
                    localization.getString("DIALOG_CANT_FIND_MD5_ALGORITHM")
                );
                
                return;
            }
        }
        else
        {
            pwdMd5 = pwd;
        }
        
        log.trace("Password hash obtained, now trying login/pwd on server.");
        
        log.trace("Checking if user wants to save his authentification.");
        
        final Config config = Config.getInstance();
        final Account account = config.getAccounts().get(config.getSelectedAccount());
        final AccountServerConfig accountServerConfig = account.getServerConfigs().get(account.getServer());
        
        if (accountServerConfig.isAuthentificationSaveable())
        {
            log.trace("Saving new login/pwd.");
            
            accountServerConfig.setUsername(login);
            accountServerConfig.setPassword(pwdMd5);
            
            config.save();
        }
        
        log.trace("Displaying wait window");
        
        final WWait wait = WWait.getInstance();
        
        try
        {
            wait.hideAndBegin(wLoginShell);
        }
        catch (final ThreadAlreadyRunningException tare)
        {
            log.error("A waiting window is already running, I cannot continue until it is closed.");
            
            EasyMessageBox.error(
                localization.getString("DIALOG_TITLE_ERROR"),
                localization.getString("DIALOG_PROCESS_ALREADY_RUNNING")
            );
            
            return;
        }
        
        log.trace("Creating & starting uploader.");
        
        final NetUploader uploader = new NetUploader(login, pwdMd5);
        uploader.start();
        
        wait.reset();
        
        long timer = System.currentTimeMillis();
        while (uploader.isAlive())
        {
            if (System.currentTimeMillis() - timer > 100)
            {
                wait.step();
                timer = System.currentTimeMillis();
            }
            
            if ( wLoginShell.getDisplay().readAndDispatch() == false)
            {
                wLoginShell.getDisplay().sleep();
            }
        }
        
        wait.finish();
        
        if (uploader.hasMessage())
        {
            if (uploader.getLastMessage().isError())
            {
                EasyMessageBox.error(
                    uploader.getLastMessage().getTitle(),
                    uploader.getLastMessage().getContents()
                );
            }
            else if (uploader.getLastMessage().isInfo())
            {
                EasyMessageBox.info(
                    uploader.getLastMessage().getTitle(),
                    uploader.getLastMessage().getContents()
                );
            }
        }
        
        if (uploader.getReturnedStatus() != null && uploader.getReturnedStatus().length() > 0)
        {
            log.trace("Upload successful, now parsing data.");
            
            final Result r = ResultParser.parse(uploader.getReturnedStatus());
            
            if (ResultParser.hasMessage())
            {
                if (ResultParser.getLastMessage().isError())
                {
                    EasyMessageBox.error(
                        ResultParser.getLastMessage().getTitle(),
                        ResultParser.getLastMessage().getContents()
                    );
                }
                else if (ResultParser.getLastMessage().isInfo())
                {
                    EasyMessageBox.info(
                        ResultParser.getLastMessage().getTitle(),
                        ResultParser.getLastMessage().getContents()
                    );
                }
            }
            
            if (r != null)
            {
                log.trace("Parsing successful, now displaying recap window.");
                
                new WRecap(wLoginShell.getParent().getShell(), r);
            }
            
            wLoginShell.dispose();
        }
    }
}
